/* what is this ? */
/* header file */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include "socket.h"
#include "threadpool_02.h"

/* macro definition */
#define PAGESIZE    4096
#define MAXEVENTS   256
#define MILLITIMEOUT    (20 * 1000)
/* type declaration  */
typedef int data_t;

typedef struct{
    int listenfd;
    threadpool_t* tpool;
}receptionist_args_t;

typedef struct {
    int workfd;
}wait_args_t;

/* variable definition  */


/* function declaration */
void* receptionist(void*);
void* waiter(void*);


int main(int argc, char** argv)
{
    assert(argc == 2);

    int listenfd = open_listenfd(argv[1]);

    threadpool_t tpool;     // 创建并初始化线程池
    tpool_init(&tpool, NTHREAD);

    printf("server.c\\main(): "
           "submit receptionist task\n");
    
    // 准备接待员例程任务
    thread_task_t receptionist_task;
    receptionist_task.info = "receptionist task";
    // 接待员例程函数
    receptionist_task.routine = receptionist;
    // 接待员例程参数
    receptionist_args_t receptionist_args;
    receptionist_args.listenfd = listenfd;
    receptionist_args.tpool = &tpool;
    receptionist_task.args = (void*)&receptionist_args;
    // 提交接待员任务 
    tpool.submit_task(&tpool, &receptionist_task);
    printf("server.c\\receptionist(): "
            "receptionist task submitted\n");

    printf("server.c\\main(): "
           "server is ready now\n");
    
    sleep(600);
    return 0;
}



void* receptionist(void* args)
{
    receptionist_args_t* paras = (receptionist_args_t*)args;
    int listenfd = paras->listenfd;
    threadpool_t* tpool = paras->tpool;

    printf("server.c\\receptionist(): "
           "start epoll listening\n");

    int epfd = epoll_create(1); // 无意义参数，保持正数即可

    struct epoll_event listen_event;    // 添加epoll监听事件
    listen_event.data.fd = STDIN_FILENO;
    listen_event.events = EPOLLIN;
    epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &listen_event);
    listen_event.data.fd = listenfd;
    epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &listen_event);

    while(1){
        printf("server.c\\receptionist(): "
           "wating for connection request of client\n");
        
        struct epoll_event ready_events[MAXEVENTS];
        epoll_wait(epfd, ready_events, 
                   MAXEVENTS, MILLITIMEOUT);    // timeout standfor milliseconds 
                                                // that function will block
                                                // pthread_mutex_lock(&tpool->threads_lock); // 此处不需要加锁，一来为了提高效率，二来此处不写size，只要任何时候读到size小于2就可以退出
                                                // if(tpool->size < 2){// 启动退出程序}
                                                // pthread_mutex_unlock(&tpool->threads_lock);

        for(int i=0; i<MAXEVENTS; i++){
            if(ready_events[i].data.fd == STDIN_FILENO){
                // 如果收到输入为EXIT，启动退出程序
                char buffer[PAGESIZE];
                int read_count = read(STDIN_FILENO, buffer, PAGESIZE);
                buffer[read_count] = 0;
                if((strcmp(buffer, "EXIT"))==0){
                    tpool_destroy(tpool);
                    pthread_exit(NULL);
                }
            }
            if(ready_events[i].data.fd == listenfd){
    puts("1111");
                int connfd = server_accept(listenfd);
                
                printf("server.c\\receptionist(): "
                       "submit waiter task\n");

                // 准备waiter任务
                thread_task_t waiter_task;
                // 设置waiter任务参数
                wait_args_t waiter_args;
                waiter_args.workfd = connfd;

                waiter_task.routine = waiter;
                waiter_task.args = (void*)&waiter_args;
                // 提交waiter任务
                tpool->submit_task(tpool, &waiter_task);
                printf("server.c\\receptionist(): "
                       "waiter task submitted\n");
            }
        }
    }//while 

    tpool_destroy(tpool);
    pthread_exit(NULL);
}


void* waiter(void* args)
{
    wait_args_t* waitargs = (wait_args_t*)args;
    int workfd = waitargs->workfd;
    printf("server.c\\waiter():"
           "waiter %lu is serving client with workfd %d\n",
           pthread_self(), workfd);

    char buffer[PAGESIZE];
    int read_count;

    while(1){
        // 读取客户端请求下载的文件名
        read_count = recv(workfd, buffer, PAGESIZE, 0);
        buffer[read_count] = '\0'; // 这行似乎不需要，因为读到PAGESIZE个字符
        //printf("%s\n", buffer);

        if(read_count == 0){    // 如果对端关闭,结束服务，跳出循环
            printf("server.c\\waiter(): "
                   "thread %lu report:client disconnected, mission cancelled\n",
                   pthread_self());
            break;
        }

        int download_filefd = open(buffer, O_RDONLY);
        //printf("download_filefd = %d\n", download_filefd);
        /*if(download_filefd < 0){    
            strncpy(buffer, "404: No such file in server\n", PAGESIZE);
            send(workfd, buffer,PAGESIZE, MSG_NOSIGNAL);
        }*/ 

        if(download_filefd < 0){
            printf("server.c\\waiter(): "
                   "404: No such file in server\n");
            close(download_filefd);
            close(workfd);
            return NULL;
        }

        read_count = read(download_filefd, buffer, PAGESIZE);
        printf("read_count = %d\n",read_count);
        while(read_count > 0){
            send(workfd, buffer, read_count, MSG_NOSIGNAL);
            read_count = read(download_filefd, buffer, PAGESIZE);
        }
        printf("server.c\\waiter(): "
               "waiter %lu send download file to workfd %d finished\n", 
               pthread_self(), workfd);

        // clean up
        close(download_filefd);
    }

    close(workfd);
    return NULL;
}


